#ifndef __CMATH_H__
#define __CMATH_H__
#include "../PreDefine.h"

#define TableSize			256
#define COS_SIN_SHIFT		12
#define USE_INSIDE_POLYGON

#define MATH_INDEX			182
//#include "Stream.h"
#include "Point.h"

class CPolygon;
class Point2D;

class CMath
{
public:
	//static void LoadFile(void* object, CFileStream *pFS);
	CMath(void){};
	~CMath(void){};

	static short* sRandTable;
	static fx16 Cos(int a);
	static fx16 Sin(int a);

	static int floor(float v)
	{
		if(v - (int)v == 0)
			return (int)v;
		return (int)v + 1;
	}

	static int round(float v)
	{
		return (int)(v + 0.5f);
	}

	static int sign(int v)
	{
		if(v==0)
			return 0;
		if(v>0)
			return 1;
		return -1;		
	}

	static   unsigned   intsqrt_16(unsigned   long   M)   
	{   
          unsigned   int   N,i;   
          unsigned   long   tmp,ttp;   
          if(M==0)return   0;   
          N=0;   
          tmp=(M>>30);   
          M<<=2;   
          if(tmp>1)   
          {   
                  N++;   
                  tmp-=N;   
          }   
          for(i=15;i>0;i--)   
          {   
                  N<<=1;   
                  tmp<<=2;   
                  tmp+=(M>>30);   
                  ttp=N;   
                  ttp=(ttp<<1)+1;   
                  M<<=2;   
                  if(tmp>=ttp)   
                  {   
                          tmp-=ttp;   
                          N++;   
                  }   
          }   
          return   N;   
	}   

	inline static int  Abs(int a){ return a >= 0 ? a : -a;};
	inline static int  ATan(int x, int y){ return Atan2i(x, y) * 360 / 2048;};

#if WIN32
	//shift 12
	inline static int  ACos(int a){ return ACosinus(a << 2);};
	inline static int  ASin(int a){ return ASinus(a << 2);};	
//	inline static int  ATan(int x, int y){ return Atan2i(x, y) * 360 / 2048;};
#endif
	inline static int Fast_Distance_2D(int x, int y)
	{
		x = CMath::Abs(x);
		y = CMath::Abs(y);
		int nMin = CMath::Min(x, y);
		return (x + y - (nMin >> 1) - (nMin >> 2) + (nMin >> 4));
	}
	// the result need left shift 8
	inline static void Vector2DNormalize(Point2D &p)
	{
		// normalize
		int nLength = Fast_Distance_2D(p.x, p.y);
		if (nLength != 0)
		{
			p.x = (p.x << 8) / nLength;
			p.y = (p.y << 8) / nLength;
		}
		else
		{
			p.x = 0;
			p.y = 0;
		}
	}
	inline static int GetDistance(Point2D &a, Point2D &b)
	{
		Point2D c = a;
		c -= b;
		return Fast_Distance_2D(c.x, c.y);
	}		
	//a : 0 - 360 / 2pi
	inline static int  ToDSAngle(int a)
	{
		return (a * 0x10000 / 360) & 0xFFFF;	
	}
	
	//max min
	inline static int Min(int a, int b){return a < b ? a : b;};
	inline static int Max(int a, int b){return a < b ? b : a;};
	
	//random
	static int  Rand(int min, int max);
	static void InitRandomTable(int min, int max);
	static int  GetRandFromTable();
	static float GetGLRand(float lo, float hi, int divisions = 1000);
	// max common divisor
	static int GenMaxCommDivisor(int iDividend, int iDivisor)
	{
		int iTemp = 0;
		if(iDividend < iDivisor)
		{
			iTemp = iDivisor;
			iDivisor = iDividend;
			iDividend = iTemp;
		}
		iTemp = 0;
		while((iTemp = iDividend % iDivisor) != 0)
		{
			iDividend = iDivisor;
			iDivisor = iTemp;
		}

		return iDivisor;
	}
//private:
	static bool sbInit;
	
	static int sRadomTable[TableSize];	
	static int sRandomTableSize;
	static int sRandomTableSize_Ini;


	static int m_RandCounter;
	static int m_OldRand;

	static unsigned long m_randomSeed;
	static long m_counter;

    static void SetRandomSeed(unsigned long seed);
    static unsigned int NextRandom(int bits);

	//shift 14
	static int  ACosinus(int aiCosinus);
	static int  ASinus(int aiSinus );	
	static int  Atan2i(int x, int y);

#ifdef USE_INSIDE_POLYGON
	static int multiply( Point2D& p1 , Point2D& p2 , Point2D& p0 );
public:
	static bool online( Point2D& a,Point2D& b, Point2D& p );
	static bool inter_SS( Point2D& a1,Point2D& a2,Point2D& b1,Point2D& b2);
	static bool inter_SS1( Point2D& a1,Point2D& a2,Point2D& b1,Point2D& b2);
	static bool insidePolygon( int& vcount , Point2D ver[] , Point2D& point );
	
	// RUIZD: Change
	// static bool insidePolygon( Polygon& polygon , Point2D& point );

#endif
};

int GetRand(int low = -1,int high = -1);

#endif